package com.tencent.system.service.impl;

import com.tencent.basic.annotation.PreAuthorize;
import com.tencent.basic.util.Classutil;
import com.tencent.system.domain.Permission;
import com.tencent.system.mapper.PermissionMapper;
import com.tencent.system.service.IPermissionScanService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.*;

import java.io.File;
import java.io.FileFilter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
  * 自定义注解扫描 获注解内容 保存数据到t_permission表中
  */
@Service
public class PermissionScanServiceImpl implements IPermissionScanService {

	// 读取到要扫描注解的包 - 找到类 - 找到方法 - 找到注解扫描

    private static final String  PKG_PREFIX   = "com.tencent.";
    private static final String  PKG_SUFFIX   = ".controller";

    @Autowired
    private PermissionMapper permissionMapper;

    /**
     * 扫描权限注解业务类
     */
    @Override
    public void scanPermission() {
        /* 
			获取target/classes/com/tencent/下面所有的模块目录
			this.getClass() - 当前类PermissionScanServiceImpl 
			|- 编译后放在放在target下面的classes <- .getResource("/").getPath() 就是找到这个classes的绝对路径
			|- "/com/tencent/" - 这个路径下的/com/tencent/ 下的所有包
		*/
        String path = this.getClass().getResource("/").getPath() + "/com/tencent/";
		
		// 将这个路径初始化为一个file - 将tencent这个包搞成一个文件
        File file = new File(path);
		
		// file.listFiles 列出file这个文件夹下的所有文件
        File[] files = file.listFiles(new FileFilter() { // 过滤
            @Override
            public boolean accept(File file) { // 过滤的是我们获取的file(tencent)文件夹
				// 如果你是Directory[是文件夹] 就返回 [basic,org,pet,product,system,user]
                return file.isDirectory();
            }
        });


        // 获取com.tencent.*.controller里面所有的类
        Set<Class> clazzes = new HashSet<>();
		// 遍历files - 也就是获取出来的一个一个文件夹 - basic / org / system / user / pet / product
        for (File fileTmp : files) {
            System.out.println("===============权限注解解析：获取所有的包==============");
            System.out.println(fileTmp.getName());
			// 拼接 com.tencent + basic / org / system / user + .controller包下的所有字节码对象 装进Set集合
            clazzes.addAll(Classutil.getClasses(PKG_PREFIX+fileTmp.getName()+PKG_SUFFIX));
        }

		// 1.此时clazzes中是所有controller包下所有字节码对象【com.tencent.basic.controller.User.class】
        //      |-- 遍历clazzes 每一个对象就是 每一个字节码对象[User.class]
        for (Class clazz : clazzes) {
			// 2.遍历controller[字节码对象 也就是我们的类]中的方法
            Method[] methods = clazz.getMethods();
			
			// 2.1 这个controller[字节码对象 也就是我们的类]中没有方法 就滚犊子
            if (methods == null || methods.length<1) {
                return; 
			}	
			// 2.2 这个controller中有方法
			// 3.方法上是否打了注解@PreAuthorize - 打了就是授权了才能访问的 没打就是不授权也可以访问
            for (Method method : methods) {
				// 当前方法的请求uri
                String uri = getUri(clazz, method);
                try {
					// 获取@PreAuthorize注解
                    PreAuthorize preAuthorizeAnno = method.getAnnotation(PreAuthorize.class);
					
                    // 3.2 如果没有 就不管
					if (preAuthorizeAnno == null) {
						// 跳过
                        continue;
					}
					
					// 3.1 如果有注解 需要拿到注解内容(name和sn)保存到t_permission
                    String name = preAuthorizeAnno.name();
                    String permissionSn = preAuthorizeAnno.sn();
					
					// 通过sn查找t_permission表中是否存在该条permission数据
                    Permission permissionTmp = permissionMapper.loadBySn(permissionSn);
					
                    // 如果不存在就添加
                    if (permissionTmp == null) {
                        Permission permission = new Permission();
                        permission.setName(name);       // t_permission表中的权限名
                        permission.setSn(permissionSn); // t_permission表中的权限编号
                        permission.setUrl(uri);         // t_permission表中的权限路径
                        permissionMapper.save(permission);
                    } else {
                        // 如果存在就修改
                        permissionTmp.setName(name);
                        permissionTmp.setSn(permissionSn);
                        permissionTmp.setUrl(uri);
                        permissionMapper.update(permissionTmp);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }


	/**
	  * 获取方法上的请求路径
	  * @param clazz    哪一个类
	  * @param method   哪一个方法
	  * @return
	  * t_permission表中的url  //@RequestMapping("/department") //@GetMapping("/{id}")
	  */
    //
    private String getUri(Class clazz, Method method) {
        //获取类上的请求路径：/department
        String classPath = "";
        Annotation annotation = clazz.getAnnotation(RequestMapping.class);
        if (annotation!=null){
            RequestMapping requestMapping = (RequestMapping) annotation;
            String[] values = requestMapping.value();
            if(values!=null&&values.length>0){
                classPath = values[0];
                if (!"".equals(classPath)&&!classPath.startsWith("/"))
                    classPath="/"+classPath;
            }
        }
        //以下是获取方法上的请求路径：/{id}
        GetMapping getMapping =  method.getAnnotation(GetMapping.class);
        String methodPath = "";
        if (getMapping!=null){
            String[] values = getMapping.value();
            if(values!=null&&values.length>0){
                methodPath = values[0];
                if (!"".equals(methodPath)&&!methodPath.startsWith("/"))
                    methodPath="/"+methodPath;
            }
        }
        PostMapping postMapping =  method.getAnnotation(PostMapping.class);
        if (postMapping!=null){
            String[] values = postMapping.value();
            if(values!=null&&values.length>0){
                methodPath = values[0];
                if (!"".equals(methodPath)&&!methodPath.startsWith("/"))
                    methodPath="/"+methodPath;
            }
        }
        DeleteMapping deleteMapping =  method.getAnnotation(DeleteMapping.class);
        if (deleteMapping!=null){
            String[] values = deleteMapping.value();
            if(values!=null&&values.length>0){
                methodPath = values[0];
                if (!"".equals(methodPath)&&!methodPath.startsWith("/"))
                    methodPath="/"+methodPath;
            }
        }
        PutMapping putMapping =  method.getAnnotation(PutMapping.class);
        if (putMapping!=null){
            String[] values = putMapping.value();
            if(values!=null&&values.length>0){
                methodPath = values[0];
                if (!"".equals(methodPath)&&!methodPath.startsWith("/"))
                    methodPath="/"+methodPath;
            }

        }
        PatchMapping patchMapping = method.getAnnotation(PatchMapping.class);
        if (patchMapping!=null){
            String[] values = patchMapping.value();
            if(values!=null&&values.length>0){
                methodPath = values[0];
                if (!"".equals(methodPath)&&!methodPath.startsWith("/"))
                    methodPath="/"+methodPath;
            }
        }
        RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
        if (requestMapping!=null){
            String[] values = requestMapping.value();
            if(values!=null&&values.length>0){
                methodPath = values[0];
                if (!"".equals(methodPath)&&!methodPath.startsWith("/"))
                    methodPath="/"+methodPath;
            }
        }
        return classPath+methodPath;  // /department/{id}
    }

    private String getPermissionSn(String value) {
        String regex = "\\[(.*?)]";
        Pattern p = Pattern.compile("(?<=\\()[^\\)]+");
        Matcher m = p.matcher(value);
        String permissionSn =null;
        if (m.find()){
            permissionSn= m.group(0).substring(1, m.group().length()-1);
        }
        return permissionSn;
    }

    public static void main(String[] args) {
        String regex = "\\[(.*?)]";
        String text = "hasAuthority('permission:add')";
        Pattern p = Pattern.compile("(?<=\\()[^\\)]+");
        Matcher m = p.matcher(text);
        if (m.find()) {
            System.out.println(m.group(0).substring(1, m.group().length()-1));
        }
    }
}
